package ru.sgu.diploma.practic.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import ru.sgu.diploma.practic.domain.model.Automat;
import ru.sgu.diploma.practic.domain.model.GeometricModel;
import ru.sgu.diploma.practic.domain.model.Point;
import ru.sgu.diploma.practic.errors.ApplicationConfigurationException;
import ru.sgu.diploma.practic.errors.FatalException;
import ru.sgu.diploma.practic.errors.NextLetterException;
import ru.sgu.diploma.practic.errors.TranslateException;
import ru.sgu.diploma.practic.service.*;
import ru.sgu.diploma.practic.utils.ConfiguratorUtils;
import ru.sgu.diploma.practic.utils.GeometricModelUtils;

import javax.imageio.ImageIO;
import javax.security.auth.login.Configuration;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

/**
 * User: datmakin
 * Date: 14.03.11
 * Email: atmakin.dv@gmail.com
 */
public class ApplicationImpl implements Application {

    @Autowired
    StatesGenerator statesGenerator;

    @Autowired
    AutomatGenerator automatGenerator;

    @Autowired
    AutomatUltraMetricResultConverter automatUltraMetricResultConverter;

    @Autowired
    ImageConstructor imageConstructor;

    @Autowired
    private TranslateFunction determineFunctionTranslater;



    private Integer scale;
    private String fileName;

    public void configurate(String[] args) throws ApplicationConfigurationException {
        statesGenerator.setLength(ConfiguratorUtils.findLength(args));
//        try {
//            this.automat = automatGenerator.generateAutomatFromFile(ConfiguratorUtils.findPath(args));
//        } catch (Exception e) {
//            throw new ApplicationConfigurationException(e.getMessage());
//        }
        determineFunctionTranslater.generateFunctionForMod(ConfiguratorUtils.findMod(args));
        automatUltraMetricResultConverter.setMaxn(ConfiguratorUtils.findMAXN(args));
        this.scale = ConfiguratorUtils.findScale(args);
        this.fileName = ConfiguratorUtils.findName(args);
    }

    public void run() throws FatalException {

//        String[] input = {"1", "0", "1", "0", "1", "1"};
        List<Point> pointList = new LinkedList<Point>();
        for (int a = 0; a < 100000; a++) {
            String[] input = statesGenerator.generateStateForAlphabet(determineFunctionTranslater.getAlphabet());
            String[] output = null;
            try {
                output = determineFunctionTranslater.translate(input);
            } catch (TranslateException e) {
                throw new FatalException(e.getMessage());
            }

            List<Point> prPoint = null;
            try {
                prPoint = automatUltraMetricResultConverter.convert(input, output, determineFunctionTranslater.getAlphabet());
            } catch (NextLetterException e) {
                throw new FatalException(e.getMessage());
            }
            pointList.addAll(prPoint);

            if (a < 10000 && (a % 1000 == 0))  {
                GeometricModel geometricModel = new GeometricModel();
                geometricModel.setPointList(pointList);
                geometricModel.setImageResolution(GeometricModelUtils.calculateResolution(geometricModel));
                BufferedImage bufferedImage = imageConstructor.constructWithScale(geometricModel, scale);
                bufferedImage = GeometricModelUtils.verticalflip(bufferedImage);

                save(bufferedImage, fileName + "_" + a + "_");
            } else if (a % 10000 == 0) {
                GeometricModel geometricModel = new GeometricModel();
                geometricModel.setPointList(pointList);
                geometricModel.setImageResolution(GeometricModelUtils.calculateResolution(geometricModel));
                BufferedImage bufferedImage = imageConstructor.constructWithScale(geometricModel, scale);
                bufferedImage = GeometricModelUtils.verticalflip(bufferedImage);

                save(bufferedImage, fileName + "_" + a + "_");
            }

        }

        GeometricModel geometricModel = new GeometricModel();
        geometricModel.setPointList(pointList);
        geometricModel.setImageResolution(GeometricModelUtils.calculateResolution(geometricModel));
        BufferedImage bufferedImage = imageConstructor.constructWithScale(geometricModel, scale);
        bufferedImage = GeometricModelUtils.verticalflip(bufferedImage);

        save(bufferedImage, fileName + "_");

    }


    private void save(BufferedImage bufferedImage, String name) {
        File outputfile = new File(name + ".png");
        try {
            ImageIO.write(bufferedImage, "png", outputfile);
        } catch (IOException e) {
            System.out.print("fatal error while saving result: " + e.getMessage());
            System.exit(0);
        }

    }

    public String[] getNextToken(String input[], Integer length) {
        String[] result = new String[length];
        for (int i = input.length - length; i < input.length; i++) {
            try {
                result[i - (input.length - length)] = input[i];
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public StatesGenerator getStatesGenerator() {
        return statesGenerator;
    }

    public void setStatesGenerator(StatesGenerator statesGenerator) {
        this.statesGenerator = statesGenerator;
    }

    public AutomatGenerator getAutomatGenerator() {
        return automatGenerator;
    }

    public void setAutomatGenerator(AutomatGenerator automatGenerator) {
        this.automatGenerator = automatGenerator;
    }

    public AutomatUltraMetricResultConverter getAutomatUltraMetricResultConverter() {
        return automatUltraMetricResultConverter;
    }

    public void setAutomatUltraMetricResultConverter(AutomatUltraMetricResultConverter automatUltraMetricResultConverter) {
        this.automatUltraMetricResultConverter = automatUltraMetricResultConverter;
    }

    public ImageConstructor getImageConstructor() {
        return imageConstructor;
    }

    public void setImageConstructor(ImageConstructor imageConstructor) {
        this.imageConstructor = imageConstructor;
    }

    public Integer getScale() {
        return scale;
    }

    public void setScale(Integer scale) {
        this.scale = scale;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public TranslateFunction getDetermineFunctionTranslater() {
        return determineFunctionTranslater;
    }

    public void setDetermineFunctionTranslater(TranslateFunction determineFunctionTranslater) {
        this.determineFunctionTranslater = determineFunctionTranslater;
    }
}
